home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Tool Chest / Dev.CD Feb 97 TC.toast / Sample Code / QuickTime / JPEG Sample / Source / displays.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-22  |  12.2 KB  |  483 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2. #
  3. #        displays.c
  4. #
  5. #        This segment handles the Display Manager notification and
  6. #        repositions application windows in response.
  7. #
  8. #        Author(s):     Michael Marinkovich & Guillermo Ortiz
  9. #                    Apple Developer Technical Support
  10. #                    marink@apple.com
  11. #
  12. #        Modification History: 
  13. #
  14. #            4/3/96        MWM     Initial coding                     
  15. #
  16. #        Copyright © 1992-96 Apple Computer, Inc., All Rights Reserved
  17. #
  18. #
  19. #        You may incorporate this sample code into your applications without
  20. #        restriction, though the sample code has been provided "AS IS" and the
  21. #        responsibility for its operation is 100% yours.  However, what you are
  22. #        not permitted to do is to redistribute the source as "DSC Sample Code"
  23. #        after having made changes. If you're going to re-distribute the source,
  24. #        we require that you make it clear in the source that the code was
  25. #        descended from Apple Sample Code, but that you've made changes.
  26. #
  27. *************************************************************************************/
  28.  
  29. #include <Events.h>
  30. #include <ToolUtils.h>
  31. #include <Gestalt.h>
  32. #include <OSUtils.h>
  33.  
  34.  
  35. #include "App.h"
  36. #include "Proto.h"
  37.  
  38. DMNotificationUPP        gDMNUPP;
  39. ProcessSerialNumber        gThePSN;
  40.  
  41.  
  42. //----------------------------------------------------------------------
  43. //
  44. //    InstallDMNotification - tell DM that we want to be notified by callback.
  45. //                      
  46. //                      
  47. //----------------------------------------------------------------------
  48.  
  49. OSErr InstallDMNotification(void)
  50. {
  51.     OSErr                    err;
  52.     ProcessSerialNumber        thePSN;
  53.     
  54.     // use our process number so when we get called
  55.     // the A5 is ours
  56.     err = GetCurrentProcess(&gThePSN);
  57.     
  58.     if (err == noErr) {
  59.         gDMNUPP = NewDMNotificationProc(WorldChangedProc);
  60.         err = DMRegisterNotifyProc(gDMNUPP, &gThePSN);
  61.     }
  62.     
  63.     return err;
  64.     
  65. }    
  66.  
  67.  
  68. //----------------------------------------------------------------------
  69. //
  70. //    InstallAEDMNotification - tell DM that we want to be notified by AE.
  71. //                      
  72. //                      
  73. //----------------------------------------------------------------------
  74.  
  75. OSErr InstallAEDMNotification(void)
  76. {
  77.     OSErr        err;
  78.     
  79.     err = AEInstallEventHandler(kCoreEventClass, kAESystemConfigNotice,
  80.                                 NewAEEventHandlerProc(DoAEDisplayUpdate),
  81.                                 0L, false);
  82.  
  83.     return err;
  84.  
  85. }
  86.  
  87.  
  88. //----------------------------------------------------------------------
  89. //
  90. //    RemoveDMNotification - tell DM that we no longer want to be notified.
  91. //                      
  92. //                      
  93. //----------------------------------------------------------------------
  94.  
  95. OSErr RemoveDMNotification(void)
  96. {
  97.     OSErr                    err;
  98.     
  99.         err = DMRemoveNotifyProc(gDMNUPP, &gThePSN);
  100.     
  101.     return err;
  102.     
  103. }
  104.  
  105.  
  106. //----------------------------------------------------------------------
  107. //
  108. //    WorldChangedProc - Display Manager calls this proc when a depth or  
  109. //                       mode change is made. Your application should
  110. //                       handle window repositioning here. 
  111. //----------------------------------------------------------------------
  112.  
  113. pascal OSErr WorldChangedProc(AppleEvent *event)
  114. {
  115.     OSErr                    err;
  116.  
  117.     err = HandleNotification(event);
  118.     
  119.     return noErr;
  120.     
  121. }
  122.  
  123.  
  124. //----------------------------------------------------------------------
  125. //
  126. //    DoAEDisplayUpdate - Display Manager calls this proc when a depth or  
  127. //                        mode change is made. Your application should
  128. //                        handle window repositioning here. 
  129. //----------------------------------------------------------------------
  130.  
  131. pascal OSErr DoAEDisplayUpdate(AppleEvent event,AppleEvent reply,long refCon)
  132. {
  133.     OSErr                    err;
  134.  
  135.     err = HandleNotification(&event);
  136.  
  137.     return noErr;
  138.     
  139. }
  140.  
  141.  
  142. //----------------------------------------------------------------------
  143. //
  144. //    HandleNotification - handle the AppleEvent returned by either the 
  145. //                           callback or the AppleEvent procedure.
  146. //                      
  147. //----------------------------------------------------------------------
  148.  
  149. OSErr HandleNotification(AppleEvent *event)
  150. {
  151.     OSErr                    err;
  152.     GrafPtr                    oldPort;
  153.     AEDescList                displayList;
  154.     AEDescList                aDisplay;
  155.     AERecord                oldConfig,newConfig;
  156.     AEKeyword                tempWord;
  157.     DisplayIDType            displayID;
  158.     unsigned long            returnType;
  159.     long                    count;
  160.     Rect                    oldRect, newRect;
  161.     
  162.     GetPort(&oldPort);
  163.  
  164.     // Get a list of the displays from the Display Notice AppleEvent.
  165.     err = AEGetParamDesc(event,kAEDisplayNotice,typeWildCard,&displayList);
  166.     // How many items in the list
  167.     err = AECountItems(&displayList,&count);
  168.     
  169.     while (count > 0) {     // Loop through the list.
  170.         err = AEGetNthDesc(&displayList, count, typeWildCard, &tempWord, 
  171.                                     &aDisplay);
  172.         
  173.         // Get the Old Rect.            
  174.         err = AEGetNthDesc(&aDisplay, 1, typeWildCard, &tempWord, 
  175.                            &oldConfig);
  176.         err = AEGetKeyPtr(&oldConfig, keyDeviceRect, typeWildCard, 
  177.                           &returnType, &oldRect, 8, nil);
  178.         
  179.         // Get the DisplayID so we can get the GDevice later.                
  180.         err = AEGetKeyPtr(&oldConfig, keyDisplayID, typeWildCard, 
  181.                           &returnType, &displayID, 8, nil);
  182.  
  183.         // Get the New Rect.                
  184.         err = AEGetNthDesc(&aDisplay, 2, typeWildCard, &tempWord, 
  185.                            &newConfig);
  186.         err = AEGetKeyPtr(&newConfig, keyDeviceRect, typeWildCard, 
  187.                           &returnType, &newRect, 8, nil);
  188.         
  189.         // If the New and Old rects are not the same then we can assume
  190.         // the GDevice has changed and we need to rearrange the windows.
  191.         if (err == noErr && !EqualRect(&newRect, &oldRect))
  192.             HandleDeviceChange(displayID, &newRect);
  193.  
  194.         count--;
  195.         err = AEDisposeDesc(&aDisplay);
  196.         err = AEDisposeDesc(&oldConfig);
  197.         err = AEDisposeDesc(&newConfig);
  198.  
  199.     }
  200.     
  201.     err = AEDisposeDesc(&displayList);
  202.     SetPort(oldPort);
  203.     
  204.     return err;
  205. }
  206.  
  207.  
  208. //----------------------------------------------------------------------
  209. //
  210. //    HandleDeviceChange - called when the oldconfig is different from 
  211. //                         newconfig. Will check all windows on effected 
  212. //                           device and move if needed.
  213. //----------------------------------------------------------------------
  214.  
  215. OSErr HandleDeviceChange(DisplayIDType displayID, Rect *newRect)
  216. {
  217.     OSErr        err = noErr;
  218.     GDHandle    gd;
  219.     GDHandle    onGD;
  220.     WindowRef    window;
  221.     
  222.     // Get the GDevice from the DisplayID.
  223.     err = DMGetGDeviceByDisplayID((DisplayIDType) displayID, &gd, false);
  224.  
  225.     if (err == noErr && gd != nil) {
  226.         window = FrontWindow();
  227.         
  228.         while (window != nil) {
  229.             SetPort(window); 
  230.             // which device holds the greatest portion of the window
  231.             onGD = GetGreatestDevice(window);
  232.             
  233.             // If the window is not 50% or greater on
  234.             // the desired device then pass it up.
  235.             if (onGD == gd) { 
  236.                 if (OutOfBoundsRect(gd, window, *newRect)) {
  237.                     MoveInbounds(window, gd, *newRect); 
  238.                     if (OutOfBoundsRect(gd, window, *newRect)) {
  239.                         ResizeInbounds(window, gd, *newRect);
  240.                         
  241.                         // If it is one of our document windows then we need
  242.                         // to reset the std state and the scroll bars.
  243.                         if (GetIsAppWindow(window))
  244.                             AdjustScrollbars(window, true);
  245.                     }        
  246.                 }
  247.                 ResetStdState(window);
  248.  
  249.             }    
  250.             window = (WindowRef)(((WindowPeek)window)->nextWindow);
  251.         }
  252.     }
  253.     
  254.     return err;
  255.     
  256. }
  257.  
  258.     
  259. //----------------------------------------------------------------------
  260. //
  261. //    OutOfBoundsRect -  check to see if the window is out of the device
  262. //                       rect.
  263. //                      
  264. //----------------------------------------------------------------------
  265.  
  266. Boolean OutOfBoundsRect(GDHandle gd, WindowRef window, Rect screenRect)
  267. {
  268.     Boolean        out = false;
  269.     Rect        windRect;
  270.     short        mHeight = 0;
  271.     
  272.     GetWindowRect(window, &windRect);
  273.     
  274.     if (gd == GetMainDevice())
  275.         mHeight = GetMBarHeight();
  276.  
  277.     if ((windRect.right > screenRect.right) || (windRect.bottom > screenRect.bottom))
  278.         out = true;
  279.  
  280.     if ((windRect.left < screenRect.left) || (windRect.top < screenRect.top + mHeight))
  281.         out = true;
  282.     
  283.     return out;
  284.     
  285. }
  286.     
  287.     
  288. //----------------------------------------------------------------------
  289. //
  290. //    MoveInbounds -  Move window on to desired device
  291. //                        
  292. //                      
  293. //----------------------------------------------------------------------
  294.  
  295. void MoveInbounds(WindowRef window, GDHandle gd, Rect screenRect)
  296. {
  297.     Rect        bounds;
  298.     short        mHeight = 0;
  299.     short        hGlobal;
  300.     short        vGlobal;
  301.         
  302.     GetWindowRect(window, &bounds);
  303.  
  304.     if (gd == GetMainDevice())
  305.         mHeight = GetMBarHeight();
  306.         
  307.     hGlobal = bounds.left;
  308.     vGlobal = bounds.top + kTitleBarHeight;
  309.     
  310.     // we want to make the left-top a priority so adjust it first
  311.     // as to override the bottom, right movements. This is so we
  312.     // can resize the window later. 
  313.     
  314.     if (((bounds.right - bounds.left) > (screenRect.right - screenRect.left)) ||
  315.         ((bounds.bottom - bounds.top) > 
  316.         ((screenRect.bottom - screenRect.top) - mHeight))) {
  317.         
  318.         // adjust left
  319.         if (bounds.left < screenRect.left)
  320.             hGlobal = screenRect.left + kFudgeFactor;
  321.         
  322.         // adjust top
  323.         if (bounds.top < screenRect.top + mHeight)
  324.             vGlobal = screenRect.top + kTitleBarHeight + mHeight + kFudgeFactor;
  325.  
  326.     }    
  327.     else {
  328.         // adjust left
  329.         if (bounds.left < screenRect.left)
  330.             hGlobal = screenRect.left + kFudgeFactor;
  331.         else {
  332.             // adjust right
  333.             if (bounds.right > screenRect.right)
  334.                 hGlobal = (screenRect.right - (bounds.right - bounds.left)) - kFudgeFactor;
  335.         }
  336.         
  337.         // adjust top
  338.         if (bounds.top < screenRect.top + mHeight)
  339.             vGlobal = screenRect.top + kTitleBarHeight + mHeight + kFudgeFactor;
  340.  
  341.         else {
  342.             // adjust bottom
  343.             if (bounds.bottom > screenRect.bottom)
  344.                 vGlobal = (screenRect.bottom -  kFudgeFactor -
  345.                           (bounds.bottom - bounds.top) + mHeight);
  346.         }        
  347.  
  348.     }
  349.     
  350.     MoveWindow(window, hGlobal, vGlobal,false);
  351.         
  352. }
  353.     
  354.  
  355. //----------------------------------------------------------------------
  356. //
  357. //    ResizeInbounds -  resize the window to fit in the graphics device
  358. //                        
  359. //                      
  360. //----------------------------------------------------------------------
  361.  
  362. void ResizeInbounds(WindowRef window, GDHandle gd, Rect screenRect)
  363. {
  364.     Rect        windRect;
  365.     short        h;
  366.     short        v;
  367.  
  368.     windRect = window->portRect;
  369.     // make the window bounds the size of the gdRect
  370.     // less the fudge factor.
  371.     h = windRect.right - windRect.left;
  372.     v = windRect.bottom - windRect.top;
  373.  
  374.     if (h > screenRect.right - screenRect.left)
  375.         h = ((screenRect.right - screenRect.left) - (kFudgeFactor * 2));
  376.     
  377.     if (v > screenRect.bottom - screenRect.top) {
  378.         v = ((screenRect.bottom - screenRect.top) - (kFudgeFactor * 2));
  379.         
  380.         // If we are on the main device then subtract the mBar
  381.         // height plus a fudge factor for a boundary. 
  382.         if (gd == GetMainDevice())
  383.             v -= (GetMBarHeight() + kTitleBarHeight);
  384.     }        
  385.  
  386.         
  387.     SizeWindow(window, h, v, true);
  388.  
  389. }
  390.     
  391.  
  392. //----------------------------------------------------------------------
  393. //
  394. //    GetGreatestDevice - find thw device that holds the greatest area 
  395. //                        of the window.
  396. //                      
  397. //----------------------------------------------------------------------
  398.  
  399. GDHandle GetGreatestDevice(WindowRef window)
  400. {
  401.     GDHandle    gd;
  402.     GDHandle    savedGD;
  403.     Rect        gdRect;
  404.     Rect        foundRect;
  405.     long        size;
  406.     long        greatest = nil;
  407.  
  408.     gd = DMGetFirstScreenDevice(dmOnlyActiveDisplays);
  409.     savedGD = gd;
  410.     
  411.     // Loop through the device list
  412.     while (gd != nil) {    
  413.         gdRect = (**gd).gdRect;
  414.         
  415.         GlobalToLocal(&topLeft(gdRect));
  416.         GlobalToLocal(&botRight(gdRect));
  417.         
  418.         if (SectRect(&window->portRect, &gdRect, &foundRect)) {
  419.             size = ((long)(foundRect.right - foundRect.left) * 
  420.                    (long)(foundRect.bottom - foundRect.top));
  421.             
  422.             if (size > greatest) {
  423.                 greatest = size;
  424.                 savedGD = gd;        // save the greatest device
  425.             }    
  426.         }
  427.         gd = DMGetNextScreenDevice(gd, dmOnlyActiveDisplays);
  428.     }
  429.     
  430.     return savedGD;
  431. }
  432.  
  433.  
  434. //----------------------------------------------------------------------
  435. //
  436. //    GetWindowRect - return actual window rect in global coords
  437. //                    
  438. //                    
  439. //----------------------------------------------------------------------
  440.  
  441. void GetWindowRect(WindowRef window, Rect *windRect)
  442. {    
  443.     *windRect = window->portRect;
  444.     
  445.     // add the titlebar height for actual height
  446.     windRect->top -= kTitleBarHeight;
  447.     
  448.     LocalToGlobal(&TopLeft(*windRect));
  449.     LocalToGlobal(&BotRight(*windRect));
  450.  
  451.  
  452. }
  453.  
  454. //----------------------------------------------------------------------
  455. //
  456. //    ResetStdState - since we are now on a different size screen we need
  457. //                    to change the stdState window size so our zooming
  458. //                    will work properly.  
  459. //----------------------------------------------------------------------
  460.  
  461. void ResetStdState(WindowRef window)
  462. {
  463.     Rect        screenRect;
  464.     
  465.     screenRect = window->portRect;
  466.  
  467.     LocalToGlobal(&TopLeft(screenRect));
  468.     LocalToGlobal(&BotRight(screenRect));
  469.     
  470.     // with the new interfaces we could also use the
  471.     // SetWindowStandardState procedure. 
  472.     (**(WStateDataHandle)
  473.         ((WindowPeek)window)->dataHandle).stdState = screenRect;
  474.         
  475.  
  476. }
  477.     
  478.     
  479.  
  480.     
  481.     
  482.  
  483.